#include "shading.h"

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>


GLuint create_gl_program(char const * const vertex_source,
		char const * const fragment_source) {
	GLuint vertex_id = 0;
	GLuint fragment_id = 0;
	if (vertex_source != NULL) {
		// Create a shader object
		vertex_id = glCreateShader(GL_VERTEX_SHADER);
		assert(vertex_id != 0);
	
		// Put the shader's source into the shader object
		glShaderSource(vertex_id, 1, &vertex_source , NULL);
		
		// Compile the shader object
		glCompileShader(vertex_id);
		
		// Check the shader compiled successfully
		GLint compile_status = GL_FALSE;
		glGetShaderiv(vertex_id, GL_COMPILE_STATUS, &compile_status);
		if (compile_status == GL_FALSE) {
			GLint info_log_length = 0;
			glGetShaderiv(vertex_id, GL_INFO_LOG_LENGTH, &info_log_length);
			if (info_log_length > 0) {
				char info_log[info_log_length];
				glGetShaderInfoLog(vertex_id, info_log_length, NULL,
						&(info_log[0]));
				printf("Compilation error: %s\n", &(info_log[0]));
			}
			else {
				printf("Compilation error: No information available\n");
			}
		}
	}
	
	if (fragment_source != NULL) {
		// Create a shader object
		fragment_id = glCreateShader(GL_FRAGMENT_SHADER);
		assert(fragment_id != 0);
	
		// Put the shader's source into the shader object
		glShaderSource(fragment_id, 1, &fragment_source , NULL);
		
		// Compile the shader object
		glCompileShader(fragment_id);
		
		// Check the shader compiled successfully
		GLint compile_status = GL_FALSE;
		glGetShaderiv(fragment_id, GL_COMPILE_STATUS, &compile_status);
		if (compile_status == GL_FALSE) {
			GLint info_log_length = 0;
			glGetShaderiv(fragment_id, GL_INFO_LOG_LENGTH, &info_log_length);
			if (info_log_length > 0) {
				char info_log[info_log_length];
				glGetShaderInfoLog(fragment_id, info_log_length, NULL,
						&(info_log[0]));
				printf("Compilation error: %s\n", &(info_log[0]));
			}
			else {
				printf("Compilation error: No information available\n");
			}
		}
	}

	// Create a program object
	GLuint program_id = glCreateProgram();
	assert(program_id != 0);
	
	// Attach the shader objects to the program object
	if (vertex_id != 0) {
		glAttachShader(program_id, vertex_id);
	}
	if (fragment_id != 0) {
		glAttachShader(program_id, fragment_id);
	}
	
	// Link the program object
	glLinkProgram(program_id);

	// Check the program linked successfully
	GLint link_status = GL_FALSE;
	glGetProgramiv(program_id, GL_LINK_STATUS, &link_status);
	if (link_status == GL_FALSE) {
		GLint info_log_length = 0;
		glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &info_log_length);
		if (info_log_length > 0){
			char info_log[info_log_length];
			glGetProgramInfoLog(program_id, info_log_length, NULL,
					&(info_log[0]));
			printf("Linking error: %s\n", &(info_log[0]));
		}
		else {
			printf("Linking error: No information available\n");
		}
	}
	
	// Delete the shader object
	if (vertex_id != 0) {
		glDetachShader(program_id, vertex_id);
	}
	if (fragment_id != 0) {
		glDetachShader(program_id, fragment_id);
	}
	glDeleteShader(vertex_id);
	glDeleteShader(fragment_id);
	
	return program_id;
}
